﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace SBS_Map_Editor
{
    public sealed partial class Manipulator
    {
        private void InitRotation()
        {
            Dictionary<AxisFlags, Matrix> axis_transforms = new Dictionary<AxisFlags, Matrix>();

            axis_transforms[AxisFlags.X] = Matrix.CreateRotationZ(MathHelper.PiOver2);
            axis_transforms[AxisFlags.Y] = Matrix.Identity;
            axis_transforms[AxisFlags.Z] = Matrix.CreateRotationX(MathHelper.PiOver2);

            #region Draw
            mDrawFunctions[TransformationMode.Rotation][AxisFlags.X]
                    = mDrawFunctions[TransformationMode.Rotation][AxisFlags.Y]
                    = mDrawFunctions[TransformationMode.Rotation][AxisFlags.Z]
                        = delegate(AxisFlags axis)
                        {
                            ManipulatorSettings.RotationSettings settings = mSettings.Rotation;

                            // draw a circle strip around the specified axis
                            Primitives.DrawCircleStrip(mGraphics.GraphicsDevice, Vector3.Zero, settings.InnerRadius,
                                settings.OuterRadius, 128, axis_transforms[axis]);
                        };
            #endregion

            #region Rotation
            mManipFunctions[TransformationMode.Rotation][AxisFlags.X]
                = mManipFunctions[TransformationMode.Rotation][AxisFlags.Y]
                = mManipFunctions[TransformationMode.Rotation][AxisFlags.Z]
                = delegate()
                {
                    Plane p = GetPlane(SelectedAxes);

                    Ray start_ray = GetPickRay(mInput.Start);
                    Ray end_ray = GetPickRay(mInput.End);

                    float? hits = start_ray.Intersects(p);
                    float? hite = end_ray.Intersects(p);

                    if (!hits.HasValue || !hite.HasValue)
                        return;

                    Vector3 start_position = start_ray.Position + (start_ray.Direction * hits.Value);
                    Vector3 end_position = end_ray.Position + (end_ray.Direction * hite.Value);

                    Vector3 origin_to_start = Vector3.Normalize(start_position - mTransform.Translation);
                    Vector3 origin_to_end = Vector3.Normalize(end_position - mTransform.Translation);

                    Vector3 rotation_axis = GetUnitAxis(SelectedAxes);

                    Vector3 rot_cross_start = Vector3.Normalize(Vector3.Cross(rotation_axis, origin_to_start));
                    Vector3 rot_cross_end = Vector3.Normalize(Vector3.Cross(rotation_axis, origin_to_end));

                    Vector3 start_cross_end = Vector3.Normalize(Vector3.Cross(rot_cross_start, rot_cross_end));

                    float dot = Vector3.Dot(origin_to_start, origin_to_end);
                    float rotation_angle = (float)Math.Acos(dot) * Math.Sign(Vector3.Dot(rotation_axis, start_cross_end));

                    Quaternion rot = Quaternion.Normalize(Quaternion.CreateFromAxisAngle(rotation_axis, rotation_angle));

                    mTransform.Rotation *= rot;
                };
            #endregion
        }
    }
}